package com.uduemc.biso.node.web.api.service.impl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import com.uduemc.biso.core.extities.center.Host;
import com.uduemc.biso.core.utils.JsonResult;
import com.uduemc.biso.node.core.common.folderpojo.FolderTree;
import com.uduemc.biso.node.core.common.folderpojo.type.FolderTreeType;
import com.uduemc.biso.node.core.entities.HDomain;
import com.uduemc.biso.node.core.property.GlobalProperties;
import com.uduemc.biso.node.core.utils.SitePathUtil;
import com.uduemc.biso.node.core.utils.SiteUrlUtil;
import com.uduemc.biso.node.web.api.component.RequestHolder;
import com.uduemc.biso.node.web.api.service.DomainService;
import com.uduemc.biso.node.web.api.service.HostSetupService;
import com.uduemc.biso.node.web.api.service.VirtualFolderService;
import com.uduemc.biso.node.web.api.service.hostsetup.HSVirtualFolderService;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class VirtualFolderServiceImpl implements VirtualFolderService {

	@Autowired
	private HostSetupService hostSetupServiceImpl;

	@Autowired
	private HSVirtualFolderService hSVirtualFolderServiceImpl;

	@Autowired
	private GlobalProperties globalProperties;

	@Autowired
	private RequestHolder requestHolder;

	@Autowired
	private DomainService domainServiceImpl;

	@Override
	public JsonResult upload(MultipartFile file, String directory) {
		directory = StrUtil.removePrefix(directory, "/");
		directory = StrUtil.removeSuffix(directory, "/");

		directory = StrUtil.removePrefix(directory, File.separator);
		directory = StrUtil.removeSuffix(directory, File.separator);

		// 首先验证上传的文件是否符合要求
		String validFile = validFile(file);
		if (StrUtil.isNotBlank(validFile)) {
			return JsonResult.messageError(validFile);
		}

		// 验证上传的目录是否符合要求
		String validDirectory = validDirectory(directory);
		if (StrUtil.isNotBlank(validDirectory)) {
			return JsonResult.messageError(validDirectory);
		}

		// 验证上传的目录是否存在
		String existDirectory = existDirectory(directory);
		if (StrUtil.isNotBlank(existDirectory)) {
			return JsonResult.messageError(existDirectory);
		}

		// 验证目录下文件是否存在，如果文件存在，不允许替换该文件
		String virtualFolderDirectory = makeDirectory(directory);
		String originalFilename = file.getOriginalFilename();
		String filePath = virtualFolderDirectory + File.separator + originalFilename;
		if (FileUtil.isFile(filePath)) {
			return JsonResult.messageError("文件已存在，不能上传！");
		}

		// 验证空间是否足够，如果现有空间与上传的文件之和大于可以上传的空间大小，则不允许上传！
		long space = hostSetupServiceImpl.getSpace();
		long usedSpace = hostSetupServiceImpl.getUsedSpace();
		if ((usedSpace + file.getSize()) > space) {
			return JsonResult.messageError("空间不足无法上传！");
		}

		/**
		 * 执行上传到虚拟目录动作
		 */
		// 1. 获取用户虚拟文件目录，如果不存在则创建
		File uploadFile = new File(filePath);
		File parentFile = uploadFile.getParentFile();
		if (!FileUtil.isDirectory(parentFile)) {
			if (FileUtil.mkdir(parentFile) == null) {
				log.error("系统创建 " + parentFile.toString() + " 目录失败！");
				return JsonResult.messageError("创建目录失败，请联系管理员！");
			}
		}

		// 2. 上传至真实目录下
		try {
			file.transferTo(new File(filePath));
		} catch (IOException e) {
			e.printStackTrace();
			return JsonResult.assistance();
		}

		// 3. 返回上传结果信息
		return JsonResult.messageSuccess("上传成功", 1);
	}

	@Override
	public String validFile(MultipartFile file) {
		String originalFilename = file.getOriginalFilename();
		String suffix = FileUtil.getSuffix(originalFilename).toLowerCase();
		if (StrUtil.isBlank(suffix)) {
			return "未获取到上传文件 " + originalFilename + " 的后缀！";
		}

		List<String> virtualFolderSuffix = hSVirtualFolderServiceImpl.uploadSuffix();
		if (CollUtil.isEmpty(virtualFolderSuffix)) {
			return "系统未设定可上传的文件后缀！";
		}

		if (!virtualFolderSuffix.contains(suffix)) {
			return "后缀 " + suffix + " 未被允许上传";
		}

		long virtualFolderSize = hSVirtualFolderServiceImpl.size();
		long size = file.getSize();
		long mvirtualFolderSize = (long) virtualFolderSize / (1024 * 1024);
		if (size > virtualFolderSize) {
			return "超过允许上传文件的大小" + mvirtualFolderSize + "M";
		}

		String filename = StrUtil.removeSuffix(originalFilename, "." + suffix);
		if (StrUtil.length(filename) > 200) {
			return "文件名的长度不能超过200！";
		}
		Pattern virtualFolderFilePattern = hSVirtualFolderServiceImpl.filePattern();
		Matcher matcher = virtualFolderFilePattern.matcher(filename);
		if (!matcher.matches()) {
			return "文件名 " + originalFilename + " 不符合规则，文件名只能（中文、英文、数字、空格、.、-、_）组成，文件名开头、结尾只能（中文、英文、数字）";
		}

		return null;
	}

	@Override
	public String validDirectory(String directory) {
		if (StrUtil.isBlank(directory)) {
			return null;
		}
		String[] split = directory.split("/");
		// 限定目录层级
		if (split.length > 20) {
			return "创建目录结构最多不能超过20层！";
		}
		Pattern virtualFolderDirectoryPattern = hSVirtualFolderServiceImpl.directoryPattern();
		for (String string : split) {
			Matcher matcher = virtualFolderDirectoryPattern.matcher(string);
			if (!matcher.matches()) {
				return "目录名 " + string + " 不符合规则，目录名只能（中文、英文、数字、空格）组成，目录名开头、结尾只能（中文、英文、数字）";
			}
		}
		return null;
	}

	@Override
	public String existDirectory(String directory) {
		String virtualFolderDirectory = makeDirectory(directory);
		if (!FileUtil.isDirectory(virtualFolderDirectory)) {
			return "不存在目录（" + directory + "）";
		}
		return null;
	}

	@Override
	public String makeDirectory(String directory) {
		String basePath = globalProperties.getSite().getBasePath();
		Host host = requestHolder.getHost();
		String virtualFolderPath = SitePathUtil.getUserVirtualFolderPathByCode(basePath, host.getRandomCode());
		if (!FileUtil.isDirectory(virtualFolderPath)) {
			if (FileUtil.mkdir(virtualFolderPath) == null) {
				log.error("系统创建 " + virtualFolderPath + " 目录失败！");
				return "创建目录失败，请联系管理员！";
			}
		}
		if (StrUtil.isNotBlank(directory)) {
			directory = StrUtil.removePrefix(directory, "/");
			directory = StrUtil.removeSuffix(directory, "/");

			directory = StrUtil.removePrefix(directory, File.separator);
			directory = StrUtil.removeSuffix(directory, File.separator);

			virtualFolderPath = virtualFolderPath + File.separator + directory;
		}

		return new File(virtualFolderPath).getPath();
	}

	@Override
	public JsonResult ls(String directory) {
		String makeDirectory = makeDirectory(directory);
		File[] ls = FileUtil.ls(makeDirectory);
		List<FolderTree> listFolderTree = new ArrayList<>();
		if (ArrayUtil.isNotEmpty(ls)) {
			for (File file : ls) {
				FolderTree folderTree = makeFolderTree(file);
				if (folderTree == null) {
					return JsonResult.assistance();
				}
				listFolderTree.add(folderTree);
			}
		}

		List<FolderTree> sort = CollUtil.sort(listFolderTree, (o1, o2) -> {
			if (o1.getType().isDirectory() && !o2.getType().isDirectory()) {
				return -1;
			}
			if (!o1.getType().isDirectory() && o2.getType().isDirectory()) {
				return 1;
			}

			if (NumberUtil.isNumber(o1.getName()) && NumberUtil.isNumber(o2.getName())) {
				return NumberUtil.compare(Long.valueOf(o1.getName()), Long.valueOf(o2.getName()));
			}

			return o1.getName().compareTo(o2.getName());
		});
		return JsonResult.ok(sort);
	}

	@Override
	public JsonResult loopLs(String directory) {
		String makeDirectory = makeDirectory(directory);
		List<FolderTree> listFolderTree = recursionDirectory(makeDirectory);
		return JsonResult.ok(listFolderTree);
	}

	@Override
	public JsonResult ls() {
		return ls(null);
	}

	@Override
	public JsonResult loopLs() {
		return loopLs(null);
	}

	@Override
	public JsonResult mkdirs(String directory) {
		if (StrUtil.isBlank(directory)) {
			return JsonResult.illegal();
		}
		String validDirectory = validDirectory(directory);
		if (StrUtil.isNotBlank(validDirectory)) {
			return JsonResult.messageError(validDirectory);
		}
		String makeDirectory = makeDirectory(directory);
		if (FileUtil.mkdir(makeDirectory) == null) {
			log.error("系统创建 " + makeDirectory + " 目录失败！");
			return JsonResult.messageError("创建目录失败，请联系管理员！");
		}

		return JsonResult.messageSuccess("创建目录成功！", 1);
	}

	@Override
	public JsonResult delDirectory(String directory) {
		String makeDirectory = makeDirectory(directory);
		File fileDirectory = new File(makeDirectory);
		if (!FileUtil.isDirectory(fileDirectory)) {
			return JsonResult.messageError("删除的非目录！");
		}
		if (FileUtil.isNotEmpty(fileDirectory)) {
			return JsonResult.messageError("目录必须为空才能进行删除！");
		}
		if (!FileUtil.del(fileDirectory)) {
			return JsonResult.assistance();
		}
		return JsonResult.messageSuccess("删除目录成功！", 1);
	}

	@Override
	public JsonResult loopDelDirectory(String directory) {
		String makeDirectory = makeDirectory(directory);
		File fileDirectory = new File(makeDirectory);
		if (!FileUtil.isDirectory(fileDirectory)) {
			return JsonResult.messageError("删除的非目录！");
		}

		if (!FileUtil.del(fileDirectory)) {
			return JsonResult.assistance();
		}
		return JsonResult.messageSuccess("删除目录成功！", 1);
	}

	@Override
	public JsonResult delFile(String filepath) {
		String makeDirectory = makeDirectory(filepath);
		File file = new File(makeDirectory);
		if (!file.isFile()) {
			return JsonResult.messageError(filepath + " 非有效文件路径");
		}
		if (!FileUtil.del(file)) {
			return JsonResult.assistance();
		}
		return JsonResult.messageSuccess("删除文件成功！", 1);
	}

	@Override
	public JsonResult contentFile(String filepath) {
		String makeDirectory = makeDirectory(filepath);
		File file = new File(makeDirectory);
		if (!file.isFile()) {
			return JsonResult.messageError(filepath + " 非有效文件路径");
		}
		FolderTree folderTree = makeFolderTree(file, true);
		if (folderTree == null) {
			return JsonResult.assistance();
		}
		return JsonResult.ok(folderTree);
	}

	@Override
	public JsonResult saveFile(String filepath, String content) {
		if (StrUtil.isEmpty(content)) {
			content = "";
		}
		String makeDirectory = makeDirectory(filepath);
		File file = new File(makeDirectory);
		if (!file.isFile()) {
			return JsonResult.messageError(filepath + " 非有效文件路径");
		}

		String name = file.getName();
		String suffix = FileUtil.getSuffix(name);
		List<String> contentSuffix = hSVirtualFolderServiceImpl.contentSuffix();
		if (CollUtil.isEmpty(contentSuffix)) {
			return JsonResult.assistance();
		}

		if (!contentSuffix.contains(suffix)) {
			return JsonResult.messageError("此文件不能被写入内容");
		}

		if (FileUtil.writeUtf8String(content, file) == null) {
			return JsonResult.assistance();
		}

		return JsonResult.messageSuccess("保存成功！", 1);
	}

	@Override
	public FolderTree makeFolderTree(File file) {
		return makeFolderTree(file, false);
	}

	@Override
	public FolderTree makeFolderTree(File file, boolean isContent) {
		String name = file.getName();
		String suffix = FileUtil.getSuffix(name);
		String content = "";
		if (isContent && file.isFile()) {
			List<String> contentSuffix = hSVirtualFolderServiceImpl.contentSuffix();
			if (CollUtil.isNotEmpty(contentSuffix) && contentSuffix.contains(suffix)) {
				content = FileUtil.readUtf8String(file);
			}
		}
		String path = "";
		try {
			String basePath = globalProperties.getSite().getBasePath();
			Host host = requestHolder.getHost();
			String virtualFolderPath = SitePathUtil.getUserVirtualFolderPathByCode(basePath, host.getRandomCode());
			String canonicalPath = file.getCanonicalPath();
			path = StrUtil.replace(canonicalPath, new File(virtualFolderPath).getCanonicalPath(), "");
			path = StrUtil.removePrefix(path, File.separator);
			path = StrUtil.replace(path, File.separator, "/");
		} catch (IOException e) {
			e.printStackTrace();
			log.error("file.getCanonicalPath() 异常，file: " + file.toString());
			return null;
		}
		List<FolderTree> child = null;

		FolderTreeType type = new FolderTreeType(file.isDirectory(), file.isDirectory() ? null : FileTypeUtil.getType(file), suffix);

		long lastModified = file.lastModified();

		long size = FileUtil.size(file);

		String href = path;
		String domain = requestHolder.getDefaultDomain() != null ? requestHolder.getDefaultDomain().getDomainName() : null;
		if (StrUtil.isBlank(domain)) {
			Long hostId = requestHolder.getHost().getId();
			HDomain defaultDomain;
			try {
				defaultDomain = domainServiceImpl.getDefaultDomain(hostId);
				if (defaultDomain != null) {
					domain = defaultDomain.getDomainName();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if (!StrUtil.isBlank(domain)) {
			href = "http:" + SiteUrlUtil.getSitePath(domain) + href;
		}

		FolderTree folderTree = new FolderTree(type, name, path, content, size, href, lastModified, child);
		return folderTree;
	}

	protected List<FolderTree> recursionDirectory(String fullDirectory) {
		List<FolderTree> listFolderTree = null;
		File[] ls = FileUtil.ls(fullDirectory);
		if (ArrayUtil.isNotEmpty(ls)) {
			listFolderTree = new ArrayList<>();
			for (File file : ls) {
				FolderTree folderTree = makeFolderTree(file);
				if (folderTree == null) {
					return null;
				}
				if (folderTree.getType().isDirectory()) {
					List<FolderTree> child = recursionDirectory(fullDirectory + File.separator + folderTree.getName());
					folderTree.setChild(child);
				}
				listFolderTree.add(folderTree);
			}
		}

		return listFolderTree;
	}
}
